package personal.jinhui.paprika.service;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;

import org.jivesoftware.smack.Chat;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.util.StringUtils;
import org.jivesoftware.smackx.ChatState;
import org.jivesoftware.smackx.ChatStateListener;

import android.app.Notification;
import android.app.PendingIntent;
import android.content.ContentValues;
import android.content.Intent;
import android.net.Uri;
import android.os.Environment;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.util.Log;

import personal.jinhui.paprika.PaprikaService;
import personal.jinhui.paprika.providers.MessagesHelper;
import personal.jinhui.paprika.service.aidl.IChat;
import personal.jinhui.paprika.service.aidl.IMessageListener;

/**
 * An adapter for smack's Chat class.
 */
public class PaprikaChat extends IChat.Stub {
	private static final int HISTORY_MAX_SIZE = 50;
	private static final String TAG = "ChatAdapter";
	private static final String PROTOCOL = "XMPP";

	private final Chat mAdaptee;
	private final Contact mParticipant;
	private String mState;
	private boolean mIsOpen;
	private final List<Message> mMessages;
	private final RemoteCallbackList<IMessageListener> mRemoteListeners = new RemoteCallbackList<IMessageListener>();
	private final MessageListener mMessageListener = new MessageListener();
	private UserInfo mUserInfo;
	private boolean mIsHistory;
	private String mHistoryPath;
	private PaprikaService mService;

	/**
	 * Constructor.
	 * 
	 * @param chat
	 *            The chat to adapt
	 */
	public PaprikaChat(final Chat chat, final UserInfo userInfo,
			boolean isHistory, String historyPath) {
		mAdaptee = chat;
		mUserInfo = userInfo;
		mIsHistory = isHistory;
		mHistoryPath = historyPath;
		mParticipant = new Contact(chat.getParticipant());
		mMessages = new LinkedList<Message>();
		mAdaptee.addMessageListener(mMessageListener);
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public String getParticipantJIDWithRes() throws RemoteException {
		return mParticipant.getJIDWithRes();
	}

	@Override
	public Contact getParticipant() throws RemoteException {
		return mParticipant;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void sendMessage(Message message) throws RemoteException {

		transferMessage(message);
		logMessage(message);
	}

	/**
	 * private method for sending message.
	 * 
	 * @param message
	 *            the message to send
	 */
	private void transferMessage(Message message) {
		org.jivesoftware.smack.packet.Message send = new org.jivesoftware.smack.packet.Message();
		String msgBody = message.getBody();
		send.setTo(message.getTo());
		Log.w(TAG, "message to " + message.getTo());
		send.setBody(msgBody);

		send.setThread(message.getThread());
		send.setSubject(message.getSubject());
		send.setType(org.jivesoftware.smack.packet.Message.Type.chat);
		try {
			mAdaptee.sendMessage(send);
		} catch (XMPPException e) {
			e.printStackTrace();
		}
	}

	/**
	 * send message.
	 * 
	 * @param msg
	 *            to send.
	 */
	public void injectMessage(String message) {
		Message msgToSend = new Message(mParticipant.getJIDWithRes(),
				Message.MSG_TYPE_CHAT);
		msgToSend.setBody(message);
		transferMessage(msgToSend);
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void addMessageListener(IMessageListener listen) {
		if (listen != null)
			mRemoteListeners.register(listen);
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void removeMessageListener(IMessageListener listen) {
		if (listen != null) {
			mRemoteListeners.unregister(listen);
		}
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public String getState() throws RemoteException {
		return mState;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void setState(String state) throws RemoteException {
		mState = state;
	}

	/**
	 * Get the adaptee for the Chat.
	 * 
	 * @return The real chat object
	 */
	public Chat getAdaptee() {
		return mAdaptee;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void setOpen(boolean isOpen) {
		this.mIsOpen = isOpen;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public boolean isOpen() {
		return mIsOpen;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public List<Message> getMessages() throws RemoteException {
		return Collections.unmodifiableList(mMessages);
	}

	/**
	 * Add a message in the chat history.
	 * 
	 * @param msg
	 *            the message to add
	 */
	private void logMessage(Message message) {
		if (mMessages.size() == HISTORY_MAX_SIZE)
			mMessages.remove(0);
		mMessages.add(message);

		Log.d("######", "logMessage for " + mUserInfo.getJid() + ", body is "
				+ message.getBody());

		if (!"".equals(message.getBody()) && message.getBody() != null) {
			String state = Environment.getExternalStorageState();
			if (mIsHistory && Environment.MEDIA_MOUNTED.equals(state)) {
				MessagesHelper mHelper = new MessagesHelper(mService);
				mHelper.addMessage(mUserInfo.getJid(), message.getTimestamp()
						.toString(), message.getFrom(), message.getTo(),
						message.getBody(), 0); // iserror is 0/false by default
			}
		}
	}

	/**
	 * Listener.
	 */
	private class MessageListener implements ChatStateListener {
		/**
		 * Constructor.
		 */
		public MessageListener() {
		}

		private void notifyMessage(String msgBody) {
			try {

				Log.d("#########", "kkkk notifyMessage");

				CharSequence tickerText = getParticipant().getName();

				Notification noti = new Notification(
						android.R.drawable.stat_notify_chat, tickerText,
						System.currentTimeMillis());
				noti.flags = Notification.FLAG_AUTO_CANCEL
						| Notification.FLAG_SHOW_LIGHTS;

				Intent i = new Intent(mService,
						personal.jinhui.paprika.ui.ChatActivity.class);
				i.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT
						| Intent.FLAG_ACTIVITY_SINGLE_TOP
						| Intent.FLAG_ACTIVITY_NEW_TASK);
				i.setData(getParticipant().toUri());
				PendingIntent pi = PendingIntent.getActivity(mService, 0, i,
						PendingIntent.FLAG_UPDATE_CURRENT);

				noti.setLatestEventInfo(mService, tickerText, msgBody, pi);

				mService.sendNotification(
						getParticipantJIDWithRes().hashCode(), noti);
			} catch (RemoteException e) {
				Log.e(TAG, e.getMessage());
			}
		}

		@Override
		public void processMessage(Chat chat,
				org.jivesoftware.smack.packet.Message smackMsg) {

			Log.d(TAG,
					"44444 processMessage, chat, has msg " + smackMsg.getBody());

			Message message = new Message(smackMsg);
			Log.d(TAG, "kkkk new msg " + message.getBody());

			if (!isOpen()) {

				Log.d("#########", "not open!!!");
				// notifyMessage(message.getBody());
			}

			logMessage(message);

			Log.d("#########", "logMessage");

			final int n = mRemoteListeners.beginBroadcast();
			for (int i = 0; i < n; i++) {
				IMessageListener listener = mRemoteListeners
						.getBroadcastItem(i);
				try {
					if (listener != null)
						listener.processMessage(PaprikaChat.this, message);
				} catch (RemoteException e) {
					Log.w(TAG, "Error while diffusing message to listener", e);
				}
			}
			mRemoteListeners.finishBroadcast();
		}

		/**
		 * {@inheritDoc}
		 */
		@Override
		public void stateChanged(Chat chat, ChatState state) {
			mState = state.name();
			final int n = mRemoteListeners.beginBroadcast();

			for (int i = 0; i < n; i++) {
				IMessageListener listener = mRemoteListeners
						.getBroadcastItem(i);
				try {
					listener.stateChanged(PaprikaChat.this);
				} catch (RemoteException e) {
					Log.w(TAG, e.getMessage());
				}
			}
			mRemoteListeners.finishBroadcast();
		}

	}

}
